﻿using System;
using System.Collections.Generic;
using System.Text;
using Autofac.Extensions.DependencyInjection;
using MaximServices.Common;
using MaximServices.Model;
using MaximServices.Repository;
using MaximServices.Services.MottoCrawl;
using Autofac;
using MaximServices.Enum;
using System.Linq;
using log4net;

namespace MaximServices.Services
{
    /// <summary>
    /// 词条检查服务
    /// </summary>
    public class MottoCheckServices
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(MottoCheckServices));

        private MottoBaikeRepository _mottoBaikeRepository;
        private MottoRepository _mottoRepository;
        private MockCacheServices _mockCacheServices;
        public MottoCheckServices(MottoBaikeRepository mottoBaikeRepository, MottoRepository mottoRepository, MockCacheServices mockCacheServices)
        {
            _mottoBaikeRepository = mottoBaikeRepository;
            _mottoRepository = mottoRepository;
            _mockCacheServices = mockCacheServices;
        }

        /// <summary>
        /// 自动找系统中的待匹配词条的名言
        /// </summary>
        /// <returns></returns>
        public void AutoMatchBaike()
        {
            while (true)
            {
                //按照修改时间排序，查找第一个未匹配词条的名言
                var firstOneUnMatchMotto = _mottoRepository.FindOneUnMatchMotto();

                if (firstOneUnMatchMotto == null)
                {
                    log.Info("已经找不到没有匹配词条的内容了, 自动退出任务");
                    break;
                }

                log.Info($"即将为{ firstOneUnMatchMotto.Id } 匹配词条");

                GetBaikeUrl(firstOneUnMatchMotto.Auth_Name, firstOneUnMatchMotto);

                log.Info($"{ firstOneUnMatchMotto.Id } 匹配词条完成");
            }
        }

        /// <summary>
        /// 词条不足的检测
        /// </summary>
        public void MaximNotEnougCheck()
        {
            var noticeCount = 10;

            //生效的词条数
            var effectiveMaximCount = _mottoRepository.UnUsedEffectiveMaximCount();

            if (effectiveMaximCount < noticeCount)
            {
                log.WarnFormat($"剩余词条只有 { effectiveMaximCount }，少于{ noticeCount }，邮件通知user@fofund.com");
            }
        }

        /// <summary>
        /// 匹配百科
        /// </summary>
        /// <param name="mottoId"></param>
        /// <returns></returns>
        public Motto MatchBaike(string mottoId)
        {
            var motto = _mottoRepository.FindMotto(mottoId);

            if (motto == null)
            {
                throw new Exception($"不存在ID为{mottoId}的名言");
            }

            motto.BaikeInfo = _mottoBaikeRepository.FindBaikeLogFromMottoId(motto.Id);

            if (motto.BaikeInfo == null)
            {
                var result = GetBaikeUrl(motto.Auth_Name, motto);

                if (result == null)
                {
                    //再去数据库提取一次
                    motto.BaikeInfo = _mottoBaikeRepository.FindBaikeLogFromMottoId(motto.Id);
                }
            }

            return motto;
        }

        /// <summary>
        /// 获取百科词条地址
        /// </summary>
        /// <param name="keyword"></param>
        /// <param name="motto">名言</param>
        public CrawlResult GetBaikeUrl(string keyword, Motto motto)
        {
            var platform = "baidu";

            var baikeCrawl = ServiceLocator.Instance.ResolveKeyed<IBaikeCrawl>(platform);

            if (baikeCrawl == null)
            {
                throw new Exception($"暂时不支持{platform}百科词条获取");
            }

            var mockCache = new MockCache()
            {
                CacheKey = $"key:{keyword}-{ (motto == null ? "" : motto.Id.ToString()) }",
                CacheValue = DateTime.Now.ToString(),
                CreateTime = DateTime.Now,
                Id = IdFactory.NextId
            };

            //获取词条
            var result = _mockCacheServices.LockByCache(() =>
            {
                return baikeCrawl.MatchMotto(keyword);

            }, mockCache, 10000, false);

            //如果词条内容一条未匹配到，那么标记未匹配到词条
            //如果匹配到多条，将结果添加到数据库中，将名言状态标记为多条命中
            //如果匹配到了一条，将名言标记成唯一命中

            if (motto != null && result != null)
            {
                SaveBaikeResult(result, motto);
            }

            return result;
        }

        /// <summary>
        /// 保存百科的结果
        /// </summary>
        /// <param name="result"></param>
        /// <param name="motto"></param>
        private void SaveBaikeResult(CrawlResult result, Motto motto)
        {
            motto.BaikeInfo = _mottoBaikeRepository.FindBaikeLogFromMottoId(motto.Id);

            if (motto.BaikeInfo == null)
            {
                motto.BaikeInfo = new MottoBaike();
                motto.BaikeInfo.CreateTime = DateTime.Now;
            }

            motto.BaikeInfo.ModifyTime = DateTime.Now;
            motto.BaikeInfo.Keyword = result.KeyWord;
            motto.BaikeInfo.MottoId = motto.Id;

            //如果检测到有错误, 那么将错误会写到抓取记录表
            if (!string.IsNullOrEmpty(result.Error))
            {
                motto.BaikeInfo.BaikeContent = result.Error;
                motto.BaikeInfo.BaikeCount = 0;

                //以前的词条也许还能用，所以暂时不清除
                if (!string.IsNullOrEmpty(motto.Baike_Url))
                {
                    motto.Status = MottoStatus.MatchedBaikeError;
                }
            }

            //未匹配到词条
            else if (result.MatchPageType == CrawlPageType.NOTFOUND)
            {
                motto.Status = MottoStatus.NoMatchBaike;
                motto.Baike_Url = string.Empty;

                motto.BaikeInfo.BaikeContent = string.Empty;
                motto.BaikeInfo.BaikeCount = 0;
            }

            //匹配到一条词条
            else if (result.MatchPageType == CrawlPageType.ONE)
            {
                motto.Status = MottoStatus.MatchUnqieBaike;
                motto.Baike_Url = result.Matches.First().BaiKeUrl;

                motto.BaikeInfo.BaikeContent = Json.ToJson(result.Matches);
                motto.BaikeInfo.BaikeCount = 1;
            }

            //匹配到多条词条
            else if (result.MatchPageType == CrawlPageType.MUTILATE)
            {
                motto.Status = MottoStatus.MatchMoreBaike;
                motto.Baike_Url = string.Empty;

                motto.BaikeInfo.BaikeContent = Json.ToJson(result.Matches);
                motto.BaikeInfo.BaikeCount = result.Matches.Count;
            }

            _mottoBaikeRepository.SaveBaikeInfo(motto.BaikeInfo, motto);
        }
    }
}
